/*****************************************************************
Mix3D WebGL Game Engine
Copyright (c) fantasy ( fantasy.x2x@gmail.com )
Listens:
Distributed under the Boost Software License, Version 1.0.
http://www.boost.org/LICENSE_1_0.txt
 ****************************************************************/
/**
 * @Desc    : camera
 * @Author  : fantasy(fantasy.x2x@gmail.com)
 */
//////////////////////////////////////////////////////////////////
if(typeof(Mix3D) === 'undefined')
{
  Mix3D = {};
};
(function(Mix3D){
//////////////////////////////////////////////////////////////////
Mix3D.Camera = function()
{
  Mix3D.Spatial.call(this);
  
  //frustum 
  this.near = 1;
  this.far = 1000;
  this.bottom = -1;
  this.top = 1;
  this.left = -1.3;
  this.right = 1.3;

  this.projMatrix = new Mix3D.Matrix4();
  this.invWorldMatrix = new Mix3D.Matrix4();
  this.invProjMatrix = new Mix3D.Matrix4();
};
Mix3D.Camera.prototype.constructor = Mix3D.Camera;
Mix3D.protoCopy( Mix3D.Spatial, Mix3D.Camera );

//////////////////////////////////////////////////////////////////
///
/// Perspective camera 
///
//////////////////////////////////////////////////////////////////
Mix3D.PerspCamera = function(fovDegree, aspect, near, far)
{
  Mix3D.Camera.call(this);
  
  this.fov = fovDegree !== undefined ? fovDegree : 50;
  this.aspect = aspect !== undefined ? aspect : 1;
  this.near = near !== undefined ? near : 0.1;
  this.far = far !== undefined ? far : 2000;
  
  this.updateProjMatrix();
};
Mix3D.PerspCamera.prototype.constructor = Mix3D.PerspCamera;

/**
 * Uses Focal Length (in mm) to estimate and set FOV
 * 35mm (fullframe) camera is used if frame size is not specified;
 * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
 **/
Mix3D.PerspCamera.prototype.setLens = function(focalLens, frameHeight)
{
  frameHeight = frameHeight !== undefined ? frameHeight : 24;

  this.fov = 2 * Math.atan( frameHeight / ( focalLength * 2 ) ) * ( 180 / Math.PI );
  this.updateProjMatrix();
};

Mix3D.PerspCamera.prototype.setViewOffset = function(fullWidth, fullHeight, x, y, width, height)
{
  this.fullWidth = fullWidth;
  this.fullHeight = fullHeight;
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  this.updateProjMatrix();
};

Mix3D.PerspCamera.prototype.updateProjMatrix = function()
{
  if ( this.fullWidth ) 
  {
    this.aspect = this.fullWidth / this.fullHeight;
  }

  this.top = Math.tan( Mix3D.Math.DegToRad(this.fov*0.5) ) * this.near;
  this.bottom = -this.top;
  this.left = this.aspect * this.bottom;
  this.right = this.aspect * this.top;
  
  if ( this.fullWidth ) 
  {
    var w = Math.abs( this.right - this.left );
    var h = Math.abs( this.top - this.bottom );

    this.left = this.left + this.x * width / this.fullWidth;
    this.right = this.left + ( this.x + this.width ) * w / this.fullWidth; 
    this.bottom = this.top - ( this.y + this.height ) * h / this.fullHeight;
    this.top = this.top - this.y * this.height / this.fullHeight;
  } 
  this.projMatrix.makeFrustum( this.left, this.right, this.bottom, this.top, this.near, this.far );
};

Mix3D.protoCopy( Mix3D.Camera, Mix3D.PerspCamera );
//////////////////////////////////////////////////////////////////
///
/// Orthographic camera 
///
//////////////////////////////////////////////////////////////////
Mix3D.OrthoCamera = function(left, right, top, bottom, near, far)
{
  Mix3D.Camera(this);
  this.left = left;
  this.right = right;
  this.top = top;
  this.bottom = bottom;

  this.near = ( near !== undefined ) ? near : 0.1;
  this.far = ( far !== undefined ) ? far : 2000;
  
  this.updateProjMatrix();
};

Mix3D.OrthoCamera.prototype.constructor = Mix3D.OrthoCamera;

Mix3D.OrthoCamera.prototype.updateProjMatrix = function()
{
  this.projMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far );
};
Mix3D.protoCopy( Mix3D.Camera, Mix3D.OrthoCamera );
//////////////////////////////////////////////////////////////////
})(Mix3D);// end of function(Mix3D)